package com.spring;

import com.spring.springAnnotation.Autowired;
import com.spring.springInterface.BeanFactory;
import com.spring.springInterface.ConstructorFinder;

import java.lang.reflect.Constructor;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class ConstructorMaker implements ConstructorFinder {//获取构造方法
    private BeanFactory beanFactory;

    public Constructor<?> findConstructors (Class type){
        Constructor<?>[] constructors = type.getConstructors();
        List<Constructor<?>> autoConstructorList = new ArrayList<>();
//只有一个，直接返回
        if (constructors.length == 1) {
            return constructors[0];
        }
        //获取@Autowired标注的方法
        for (Constructor<?> constructor : constructors) {
            if (constructor.isAnnotationPresent(Autowired.class)) {
                autoConstructorList.add(constructor);
            }
        }
        //如果存在多个，抛出异常
        if (autoConstructorList.size() > 1) {
            throw new RuntimeException("存在多个autowire构造方法");
        } else if (autoConstructorList.size() == 1) {
            //如果存在一个，返回该构造方法
            return autoConstructorList.get(0);
        }
        try {
            //判断是否有无参构造
            Constructor declaredConstructor = type.getDeclaredConstructor();
            return declaredConstructor;
        } catch (NoSuchMethodException e) {
            // 如果没有无参构造，再选择其他策略
            if (constructors.length > 1) {
                throw new RuntimeException("存在多个有参构造方法且没有@Autowired注解");
            }
            return constructors[0];
        }
    }
    //获取构造参数
    public Object[] getConstructorParameters (Constructor < ? > constructor) throws Exception {
        //获取参数类型
        Class<?>[] parameterTypes = constructor.getParameterTypes();
        //获取参数
        Parameter[] parameters = constructor.getParameters();
        Object[] args = new Object[parameterTypes.length];
        for (int i = 0; i < parameterTypes.length; i++) {
            Class<?> parameterType = parameterTypes[i];
            Parameter parameter = parameters[i];
            //先通过类型获取参数值
            //通过参数类型获取beanName
            List<String> list = null;
            HashMap<Class<?>, List<String>> typeMap= beanFactory.getTypeMap();
            list = typeMap.get(parameterType);
            if (list != null && list.size() == 1) {
                String beanName = list.get(0);
                args[i] = beanFactory.getBean(beanName);
            } else if (list != null && list.size() > 1) {
                //类型相同，按名字找
                for (String beanName : list) {
                    if (beanName.equals(parameter.getName())) {
                        args[i] = beanFactory.getBean(beanName);
                    }
                    if (args[i] != null) {
                        break;
                    }
                }
                if (args[i] == null) {
                    throw new RuntimeException("没有该名称的Bean");
                }
            }
        }
        return args;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }
}
